package com.linc.concurrency;

import javax.servlet.*;
import java.io.IOException;
import java.math.BigInteger;
import java.util.Arrays;

class OneValueCache {
  private final BigInteger lastNumber;
  private final BigInteger[] factors;

  public OneValueCache(BigInteger lastNumber, BigInteger[] factors) {
    this.lastNumber = lastNumber;
    this.factors = factors.clone();
  }

  public BigInteger[] getFactors(BigInteger i) {
    if (i != null && i.equals(lastNumber)) {
      return factors.clone();
    } else {
      return null;
    }
  }
}

public class VolatileCachedFactorizer implements Servlet {

  private volatile OneValueCache cache = new OneValueCache(null, null);

  @Override
  public void init(ServletConfig servletConfig) throws ServletException {}

  @Override
  public ServletConfig getServletConfig() {
    return null;
  }

  @Override
  public void service(ServletRequest servletRequest, ServletResponse servletResponse)
      throws ServletException, IOException {

    BigInteger i = new BigInteger(servletRequest.getParameter("index"));

    var factors = cache.getFactors(i);
    if (factors == null) {
      factors = factor(i);
      cache = new OneValueCache(i, factors);
    }

    servletResponse.getWriter().append(Arrays.toString(factors));
  }

  @Override
  public String getServletInfo() {
    return null;
  }

  @Override
  public void destroy() {}

  private BigInteger[] factor(BigInteger i) {
    var r = new BigInteger[i.intValue()];
    r[0] = r[1] = BigInteger.valueOf(1);
    for (int j = 2; j < r.length; j++) {
      r[j] = r[j - 1].add(r[j - 2]);
    }
    return r;
  }
}
